/*
 ************************************************************************************************
 *                                                                                              *
 *  OSA cooperative RTOS for Microchip PIC-controllers: PIC10/12/16/18/24/dsPIC                 *
 *                                                                                              *
 *  URL:            http://wiki.pic24.ru/doku.php/en/osa/ref/intro                              *
 *                  http://picosa.narod.ru                                                      *
 *                                                                                              *
 *----------------------------------------------------------------------------------------------*
 *                                                                                              *
 *  File:           osa_picc18.c                                                                *
 *                                                                                              *
 *  Compilers:      HT-PICC STD                                                                 *
 *                  HT-PICC18 STD                                                               *
 *                  Microchip C18                                                               *
 *                  Microchip C30                                                               *
 *                                                                                              *
 *  Programmer:     Timofeev Victor                                                             *
 *                  osa@pic24.ru, testerplus@mail.ru                                            *
 *                                                                                              *
 *  Description:    PICC18 specific functions overloads                                         *
 *                                                                                              *
 *                                                                                              *
 ************************************************************************************************
 */



#define OS_Init_ProcSpec()      // Empty macro for PICC18








/************************************************************************************************
 *                                                                                              *
 *                           K E R N E L   F U N C T I O N S                                    *
 *                                                                                              *
 ************************************************************************************************/


void _OS_ClrReadySetClrCanContinue (void);  /* see description below    */



/*
 ********************************************************************************
 *                                                                              *
 *  void OS_SchedRetPoint (void)                                                *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Return to sheduler with saving current task return point    *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 ********************************************************************************
 */

void OS_SchedRetPoint (void)
{
    _OS_SET_FSR_CUR_TASK();
    _OS_SavePC();
    _OS_bTaskReady = 1;
    asm("    global _OS_SchedRetPointNoSave   ");
    asm("_OS_SchedRetPointNoSave:             ");
    _PIC18_POP();
}


/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_ClearReady (void)                                                  *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Clear bReady flag and return to the sheduler with seaving   *
 *                  task return point                                           *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *                                                                              *
 ********************************************************************************
 */

asm("   global  _OS_ClearReady");
asm("_OS_ClearReady:     ");
asm("   clrf    __OS_temp, c    ");
asm("   global  __OS_ClrReadySetClrCanContinue  ");
asm("   goto    __OS_ClrReadySetClrCanContinue  ");


/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_ClearReadySetCanContinue (void)                                    *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Clear bReady flag, set bCanContinue flag and return to the  *
 *                  sheduler with seaving task return point                     *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *                                                                              *
 ********************************************************************************
 */

asm("   global  _OS_ClearReadySetCanContinue");
asm("_OS_ClearReadySetCanContinue:     ");
asm("   setf    __OS_temp, c    ");
asm("   global  __OS_ClrReadySetClrCanContinue  ");
asm("   goto    __OS_ClrReadySetClrCanContinue  ");



/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_ClrReadySetClrCanContinue (void)                                   *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Addition function. Called only by GOTO from:                *
 *                      OS_ClearReady()                                         *
 *                      OS_ClearReadySetCanContinue()                           *
 *                  Stack has pointer of task who called theese services.       *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 ********************************************************************************
 */

void _OS_ClrReadySetClrCanContinue (void)
{


    OS_Flags.bEventError = 0;

    _OS_SET_FSR_CUR_TASK();
    _OS_SavePC();

    _OS_bTaskReady = 0;

    #if defined(OS_ENABLE_TTIMERS)

        _OS_bTaskCanContinue = 0;
        if (_OS_temp & 0x01) _OS_bTaskCanContinue = 1;

    #endif

}
















/************************************************************************************************
 *                                                                                              *
 *  MAKE FSR POINTER TO OS_CUR_TASK                                                             *
 *                                                                                              *
 *  (for code reducing)                                                                         *
 *                                                                                              *
 ************************************************************************************************/

    asm("   global __OS_SET_FSR_CUR_TASK        ");
    asm("__OS_SET_FSR_CUR_TASK:                 ");
    _PIC18_ERRATA_NOP();
    asm("       movf        __OS_CurTask+0, w, c");
    asm("       movwf       __fsr + 0, c        ");
#if OS_BANK_TASKS == 0
    asm("       clrf        __fsr + 1, c        ");
#else
    asm("       movf        __OS_CurTask+1, w, c");
    asm("       movwf       __fsr + 1, c        ");
#endif
    asm("       return                          ");



















/*
 ************************************************************************************************
 *                                                                                              *
 *                            C O U N T I N G    S E M A P H O R E S                            *
 *                                                                                              *
 ************************************************************************************************
 */


//------------------------------------------------------------------------------
#ifdef OS_ENABLE_CSEM
//------------------------------------------------------------------------------


/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_Csem_Signal (OST_CSEM *pCSem)                                      *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  Increase counting semaphore. Set EventError if csem is FF...                *
 *                                                                              *
 *                                                                              *
 *  parameters:     pCSem - pointer to counting semaphore                       *
 *                                                                              *
 *  on return:      OS_IsEventError()                                           *
 *                                                                              *
 *  note:           This function overloads "osa.c"                             *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#define _OS_Csem_Signal_DEFINED
//------------------------------------------------------------------------------

void _OS_Csem_Signal (OST_CSEM *pCSem)
{
    __OS_CSEM_DI();
    OS_Flags.bEventError = 0;               // Counting semaphore overflow bit

    //------------------------------------------------------------------------------
    //
    #if OS_CSEM_SIZE == 1

        _fsr = (_FSR_TYPE)pCSem;
        _indf++;
        if (!_indf)
        {
            _indf--;
            OS_Flags.bEventError = 1;   // Set overflow bit
        }
    //------------------------------------------------------------------------------
    // For two- and four-bytes semaphores
    //
    #else
        (*pCSem)++;
        if (!*pCSem) {
            (*pCSem) = -1;
            OS_Flags.bEventError = 1;   // Set overflow bit
        }
    #endif
    //------------------------------------------------------------------------------

    __OS_CSEM_RI();
}



//------------------------------------------------------------------------------
#if defined(OS_ENABLE_INT_CSEM)
//------------------------------------------------------------------------------

/*
 ********************************************************************************
 *                                                                              *
 *   void _OS_Csem_Signal_I (OST_CSEM *pCSem)                                   *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Copy of _OS_Csem_Signal function for calling from interrupt *
 *                                                                              *
 *                                                                              *
 *  parameters:     pCSem - pointer to counting semaphore                       *
 *                                                                              *
 *  on return:      OS_IsEventError()                                           *
 *                                                                              *
 *  note:           This function overloads "osa.c"                             *
 *                                                                              *
 ********************************************************************************
 */


//------------------------------------------------------------------------------
#define _OS_Csem_Signal_I_DEFINED
//------------------------------------------------------------------------------

void _OS_Csem_Signal_I (OST_CSEM *pCSem)
{
    OS_Flags.bEventError = 0;               // Counting semaphore overflow bit

    //------------------------------------------------------------------------------
    //
    #if OS_CSEM_SIZE == 1

        _fsr = (_FSR_TYPE)pCSem;
        _indf++;
        if (!_indf)
        {
            _indf--;
            OS_Flags.bEventError = 1;   // Set overflow bit
        }
    //------------------------------------------------------------------------------
    // For two- and four-bytes semaphores
    //
    #else
        (*pCSem)++;
        if (!*pCSem) {
            (*pCSem) = -1;
            OS_Flags.bEventError = 1;   // Set overflow bit
        }
    #endif
}

//------------------------------------------------------------------------------
#endif      // _OS_Csem_Signal_I_DEFINED
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
#endif      // OS_INABLE_CSEM
//------------------------------------------------------------------------------














/*
 ************************************************************************************************
 *                                                                                              *
 *                         C R I T I C A L   S E C T I O N S                                    *
 *                                                                                              *
 ************************************************************************************************
 */

//------------------------------------------------------------------------------
#ifdef OS_ENABLE_CRITICAL_SECTION
//------------------------------------------------------------------------------


/*
 ********************************************************************************
 *                                                                              *
 *  void OS_EnterCriticalSection (void)                                         *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Enter critical section.                                     *
 *                  This function disables interrupts (with saving current      *
 *                  state) and sets system flag bInCriticalSection              *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *  note:           This function overloads "osa.c"                             *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#define OS_EnterCriticalSection_DEFINED
//------------------------------------------------------------------------------

void OS_EnterCriticalSection (void)
{
    _OST_INT_TYPE temp;
    temp = OS_DI();
    OS_Flags.bInCriticalSection = 1;

    OS_Flags.bGIE_CTemp = 0;
    if (temp & 0x80) OS_Flags.bGIE_CTemp = 1;

    OS_Flags.bGIEL_CTemp = 0;
    if (temp & 0x40) OS_Flags.bGIEL_CTemp = 1;
}



/*
 ********************************************************************************
 *                                                                              *
 *   void OS_LeaveCriticalSection (void)                                        *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Leave critical section.                                     *
 *                  This function restore interrupt state from OS_Flag temp bits*
 *                  and clears system flag bInCriticalSection                   *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *  note:           This function overloads "osa.c"                             *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#define OS_LeaveCriticalSection_DEFINED
//------------------------------------------------------------------------------

void OS_LeaveCriticalSection (void)
{
    char temp;
    OS_Flags.bInCriticalSection = 0;
    temp = 0;
    if (OS_Flags.bGIE_CTemp) temp |= 0x80;
    if (OS_Flags.bGIEL_CTemp) temp |= 0x40;
    OS_RI(temp);
}

//------------------------------------------------------------------------------
#endif      //     #ifdef OS_ENABLE_CRITICAL_SECTION
//------------------------------------------------------------------------------


















/*
 ************************************************************************************************
 *                                                                                              *
 *                                   D E L A Y S   I N   T A S K                                *
 *                                                                                              *
 ************************************************************************************************
 */

//------------------------------------------------------------------------------
#ifdef OS_ENABLE_TTIMERS
//------------------------------------------------------------------------------

/*
 ********************************************************************************
 *                                                                              *
 *   void _OS_InitDelay (_OST_TTIMER Delay)                                     *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel)                 *
 *                                                                              *
 *                  Init task timer delay.Set timer variable in task descriptor,*
 *                  sets bit bDelay and clears bit bCanContinue.                *
 *                                                                              *
 *                  _OS_CurTask must point to descriptor.                       *
 *                                                                              *
 *                                                                              *
 *  parameters:     Delay   - time of delay in system ticks                     *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *  note:           This function overloads "osa.c"                             *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#define _OS_InitDelay_DEFINED
//------------------------------------------------------------------------------

void _OS_InitDelay (_OST_TTIMER Delay)
{

    _OS_bTaskCanContinue = 0;
    _OS_bTaskDelay = 0;         // Clear bDelay to prevent timer changing in interrupt
    _OS_SET_FSR_CUR_TASK();
    _indf = *((near char*)&OS_state);

    if (Delay)
    {

        Delay ^= -1;
        Delay ++;

        _OS_CurTask->Timer = Delay;

        _OS_bTaskDelay = 1;
        _OS_bTaskReady = 1;
        _OS_SET_FSR_CUR_TASK();
        _indf = *((near char*)&OS_state);

    }
}

//------------------------------------------------------------------------------
#endif  // #ifdef OS_ENABLE_TTIMERS
//------------------------------------------------------------------------------













































/************************************************************************************************
 *                                                                                              *
 *                            S Y S T E M   F U N C T I O N S                                   *
 *                                                                                              *
 ************************************************************************************************/



/*
 ********************************************************************************
 *                                                                              *
 *   void _OS_Task_Create(_OST_INT_TYPE priority, OST_CODE_POINTER TaskAddr)    *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *   description:   (Internal function called by system kernel from service     *
 *                  OS_Task_Create)                                             *
 *                  Create task in free descriptor.                             *
 *                                                                              *
 *  parameters:     priority - value from 0 (highest) to 7 (lowest)             *
 *                  TaskAddr - pointer to C-function that contains task         *
 *                                                                              *
 *  on return:      check OS_IsError                                            *
 *                                                                              *
 *  note:           This function overloads "osa.c"                             *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#define _OS_Task_Create_DEFINED
//------------------------------------------------------------------------------

void _OS_Task_Create(_OST_INT_TYPE priority, OST_CODE_POINTER TaskAddr)
{
    OST_TASK_POINTER Task;

    OS_Flags.bError = 0;

    #if defined(OS_DISABLE_PRIORITY)
    priority = 0;
    #endif

    Task = (OST_TASK_POINTER)OS_TaskVars;
    _OS_temp = OS_TASKS;
    do {
        if (!Task->State.bEnable)
        {
            ((OST_TASK_STATE*)&priority)->bEnable = 1;
            ((OST_TASK_STATE*)&priority)->bReady = 1;

            Task->pTaskPointer = TaskAddr;
            #ifdef OS_ENABLE_TTIMERS
                Task->Timer = 0;
            #endif
            #ifdef __OSA18__
                Task->cTempFSR1 = 0;
            #endif
            *((OS_TASKS_BANK char*)&Task->State) = priority;
            if (Task == _OS_CurTask) *((NEAR char*)&OS_state) = priority;
            _fsr = (_FSR_TYPE)Task;

            // Now FSR points to current task's descriptor
            OS_Flags.bError = 0;

            return ;

        }
        Task ++;
    } while (_OS_temp--);

    // No free descriptor
    OS_Flags.bError = 1;

    return ;
}













/*
 ********************************************************************************
 *                                                                              *
 *  char OS_DI (void)                                                           *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Disable interrupt with GIE saving                           *
 *                                                                              *
 *  parameters:     none                                                        *
 *                                                                              *
 *  on return:      char - bit 7 = previous GIEH value,                         *
 *                         bit 6 = previous GIEL value                          *
 *                         bits 0..5 = 0                                        *
 *                                                                              *
 ********************************************************************************
 */

//-------------------------------------------------------------------------------
#define OS_DI_DEFINED
//-------------------------------------------------------------------------------

    asm("   global _OS_DI           ");
    asm("_OS_DI:                    ");
    asm("   dw      0xFFFF          ");
    asm("   movf    __intcon, w, c   ");
    asm("   andlw   0xC0            ");
    asm("_DIH_REPEAT:               ");
    asm("   bcf     __intcon, 7, c   ");
    asm("   btfsc   __intcon, 7, c   ");
    asm("   bra     _DIH_REPEAT     ");
    asm("   btfss   __rcon, 7, c     ");
    asm("   bra     _DI_EXIT        ");
    asm("_DIL_REPEAT:               ");
    asm("   bcf     __intcon, 6, c   ");
    asm("   btfsc   __intcon, 6, c   ");
    asm("   bra     _DIL_REPEAT     ");
    asm("_DI_EXIT:                  ");
    asm("   return                  ");
    asm("   dw      0xFFFF          ");

/*
 ********************************************************************************
 *                                                                              *
 *  char OS_RI (void)                                                           *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Restore saved by OS_DI() GIEx states                        *
 *                                                                              *
 *  parameters:     char - bit 7 = previos GIE value, bits 0..6 = 0             *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 ********************************************************************************
 */

//-------------------------------------------------------------------------------
#define OS_RI_DEFINED
//-------------------------------------------------------------------------------

    asm("   global  _OS_RI          ");
    asm("_OS_RI:                    ");
    asm("   dw      0xFFFF          ");
    asm("   btfsc   __wreg, 7, c     ");
    asm("   bsf     __intcon, 7, c   ");
    asm("   btfsc   __rcon, 7, c     ");
    asm("   btfss   __wreg, 6, c     ");
    asm("   bra     _RI_EXIT        ");
    asm("   bsf     __intcon, 6, c   ");
    asm("_RI_EXIT:                  ");
    asm("   return                  ");
    asm("   dw      0xFFFF          ");







/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_CheckEvent (char bEvent)                                           *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  waiting services)                                           *
 *                                                                              *
 *                  Check condition of bEvent. Accordint to bEvent value and    *
 *                  current state of bReady, bDelay and bCanContinue flags,     *
 *                  task becames ready to execute or still remains in waiting   *
 *                  mode.                                                       *
 *                                                                              *
 *  parameters:     bEvent - zero, or non-zero condition                        *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *  note:           This function overloads "osa.c"                             *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#define _OS_CheckEvent_DEFINED
//------------------------------------------------------------------------------

void _OS_CheckEvent (_OST_INT_TYPE bEvent)
{

    OS_Flags.bTimeout = 0;
    _OS_SET_FSR_CUR_TASK();

    if (bEvent)
    {
        if (_OS_bTaskReady) {

            #ifdef OS_ENABLE_TTIMERS

                _OS_bTaskDelay = 0; // Clear bDelay in temporary variable OS_state
                _indf &= ~0x10;     // Clear bDelay in task descriptor

            #endif

            return;
        }

        _OS_bTaskReady = 1;

    } else {
        _OS_bTaskReady = 0;
    }

    #ifdef OS_ENABLE_TTIMERS

        if (_OS_bTaskTimeout && _OS_bTaskCanContinue)
        {
            OS_Flags.bTimeout = 1;
            return;
        }

    #endif

    _PIC18_POP();
}

























/************************************************************************************************
 *                                                                                              *
 *                     W O R K   W I T H   D Y N A M I C   T I M E R S                          *
 *                                                                                              *
 ************************************************************************************************/

//-----------------------------------------------------------------
#ifdef OS_ENABLE_DTIMERS
//-----------------------------------------------------------------


/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_Dtimer_Create (OST_DTIMER *dtimer)                                 *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  service OS_Dtimer_Create)                                   *
 *                                                                              *
 *                  Add dynamic timer into list of active dynamic timers. This  *
 *                  timer will be added at first position in list.              *
 *                                                                              *
 *                                                                              *
 *  parameters:     dtimer - pointer to dynamic timer.                          *
 *                  (for PICC16 can be allocated only in bank0 and bank1)       *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *  note:           This function overloads "osa.c"                             *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#define _OS_Dtimer_Create_DEFINED
//------------------------------------------------------------------------------

void _OS_Dtimer_Create (OST_DTIMER *dtimer)
{
    _OS_temp = OS_DI();

    _fsr = (_FSR_TYPE) dtimer;
    _postinc = *((OS_BANK char*)&_OS_DTimers.Flags);
    // Here: bActive is set,
    //       bTimeout is cleared,
    //       bRun is cleared
    //       bNextEnable is copied

    _postinc = *((OS_BANK char*)&_OS_DTimers.Next + 0);
    _postinc = *((OS_BANK char*)&_OS_DTimers.Next + 1);
    _postinc = 0;
    #if  OS_DTIMER_SIZE >= 2
    _postinc = 0;
    #endif
    #if  OS_DTIMER_SIZE == 4
    _postinc = 0;
    _postinc = 0;
    #endif



    _OS_DTimers.Next = (OST_DTIMER*)dtimer;
    _OS_DTimers.Flags.bNextEnable = 1;

    OS_RI(_OS_temp);
}





/*
 ********************************************************************************
 *                                                                              *
 *  void _OS_Dtimer_Delete (OST_DTIMER *dtimer)                                 *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    (Internal function called by system kernel througth         *
 *                  service OS_Dtimer_Delete)                                   *
 *                                                                              *
 *                  Delete dynamic timer from list of active timers. It is      *
 *                  recommended to delete all unused dynamic timers to avoid    *
 *                  speed down.                                                 *
 *                                                                              *
 *  parameters:     dtimer - pointer to deleting dynamic timer                  *
 *                                                                              *
 *  on return:      none                                                        *
 *                                                                              *
 *  note:           This function overloads "osa.c"                             *
 *                                                                              *
 ********************************************************************************
 */

//------------------------------------------------------------------------------
#define _OS_Dtimer_Delete_DEFINED
//------------------------------------------------------------------------------

void _OS_Dtimer_Delete (OST_DTIMER *dtimer)
{
    OST_DTIMER *ptcb;

    char flags;
    _fsr = (_FSR_TYPE)dtimer;
    _OS_ClearIndfTimerActive;
    flags = _postinc;
    *((char*)&ptcb + 0) = _postinc;
    *((char*)&ptcb + 1) = _postinc;
    _fsr = (_FSR_TYPE)&_OS_DTimers;
REPEAT:
    if (_OS_CheckPostincTimerNextEnable)
    {
        if (_indf == *((char*)&dtimer + 0))
        {
            if (_preinc == *((char*)&dtimer + 1)){
                _OS_temp = OS_DI();
                _postdec = *((char*)&ptcb + 1);
                _postdec = *((char*)&ptcb + 0);
                if (!((OST_DTIMER_FLAGS*)&flags)->bNextEnable) _OS_ClearIndfTimerNextEnable;
                return;
            }
            _fsr--;
        }
        asm("   movf    __postinc, w, c     ");
        asm("   movff   __indf, __fsr + 1     ");
        asm("   movwf   __fsr + 0, c      ");
        goto REPEAT;
    }

}



//------------------------------------------------------------------------------
#endif  //  OS_ENABLE_DTIMERS
//------------------------------------------------------------------------------





















